package test;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import travel.caval._20091127.channelManager.CavalGetFullHotelRatesRS;
import travel.caval._20091127.hotelBooking.AvailRQOccupation;
import travel.caval._20091127.hotelBooking.AvailableEstablishment;
import travel.caval._20091127.hotelBooking.BoardPrice;
import travel.caval._20091127.hotelBooking.CavalHotelAvailabilityRQ;
import travel.caval._20091127.hotelBooking.CavalHotelAvailabilityRS;
import travel.caval._20091127.hotelBooking.CombinationPrice;
import travel.caval._20091127.hotelBooking.Exception;
import travel.caval._20091127.hotelBooking.HotelBookingServiceProxy;

/**
 * compares caval's getFullHotelrates against caval's getAvailableHotels responses
 * 
 * @author root
 *
 */
public class AvailabilityTester {
	
	/**
	 * ChannelManagerService end point url
	 */
	public static String channelManagerServiceUrl = "http://test.viajesurbis.com/serveis/caval/20091127/soap/ChannelManagerService";

	/**
	 * HotelBookingService end point url
	 */
	public static String hotelBookingServiceUrl = "http://test.viajesurbis.com/serveis/caval/20091127/soap/HotelBookingService";

	/**
	 * if true you it prints out more detailed info
	 */
	private static boolean debug = true;
	
	/**
	 * if true if makes the web service calls. If false it uses cached responses 
	 */
	public static boolean reload = false;
	
	/**
	 * if not empty it filters by hotel id
	 */
	public static String idHotel = ""; //"2477";
	
	/**
	 * if not empty it filters by room id
	 */
	public static String idRoom = "";

	/**
	 * if not empty it filters by board id
	 */
	public static String idBoard = "";

	public static void main(String[] args) throws Exception, RemoteException {		
		if (args.length < 8) {
			System.out.println("compares prices from getFullHotelRates and online availability (they should be the same)");
			System.out.println("usage: java cp=.... test.AvailabilityTester <ChannelManagerService end point url> <HotelBookingService end point url> <agentId> <login> <password> <iata> <checkin> <checkout>");
			System.out.println("to reuse cached responses also include -Dreload=false ");
		} else {
			reload = "true".equals(System.getProperty("reload", "true"));
			channelManagerServiceUrl = args[0];
			hotelBookingServiceUrl = args[1];
			test(args[2], args[3], args[4], args[5], args[6], args[7], new int[] {1,2,0});
		}
	}

	
	/**
	 * compares both responses and prints out the result
	 * 
	 * @param agentId the agent id
	 * @param login the login
	 * @param password the password
	 * @param iata airport iata's code
	 * @param checkin check in date in dd/MM/yyyy format
	 * @param checkout check out date in dd/MM/yyyy format
	 * @param occupation an array like [number of rooms, adults per room, children per room, age first child, age second child, ...]
	 * @throws Exception
	 * @throws RemoteException
	 */
	private static void test(String agentId, String login, String password, String iata, String checkin, String checkout, int[] occupation) throws Exception, RemoteException {
		CavalHotelAvailabilityRQ avrq = new CavalHotelAvailabilityRQ();
		avrq.setAgentId(agentId);
		avrq.setLogin(login);
		avrq.setPassword(password);
		avrq.setLanguage("es");
		avrq.setAirportIds(new String[] { iata });
		if (idHotel != null && !"".equals(idHotel)) avrq.setEstablishmentIds(new String[] { idHotel });
		avrq.setCheckIn(checkin);
		avrq.setCheckOut(checkout);
		Integer[] childAges = new Integer[0];
		if (occupation.length > 3) {
			childAges = new Integer[occupation.length - 3];
			for (int i = 0; i < childAges.length; i++) {
				childAges[i] = occupation[3 + i];
			}
		}
		avrq.setOccupations(new AvailRQOccupation[] { new AvailRQOccupation(occupation[1], childAges, occupation[2], occupation[0])});
		avrq.setExcludeOnRequest(true);
		
		CavalHotelAvailabilityRS avrs1 = null;
		if (reload) {
			avrs1 = new HotelBookingServiceProxy(hotelBookingServiceUrl).getAvailableHotels(avrq);		
			//serialize the List
			try {
				OutputStream file = new FileOutputStream(System.getProperty("java.io.tmpdir") + "/rs1.ser");
				OutputStream buffer = new BufferedOutputStream(file);
				ObjectOutput output = new ObjectOutputStream(buffer);
				output.writeObject(avrs1);
				output.close();
			}  
			catch(IOException ex){
				ex.printStackTrace();
			}
		}
		
		//deserialize

		try {

			InputStream file = new FileInputStream(System.getProperty("java.io.tmpdir") + "/rs1.ser");
			InputStream buffer = new BufferedInputStream(file);
			ObjectInput input = new ObjectInputStream (buffer);


			//deserialize the List
			Object o = input.readObject();
			avrs1 = (CavalHotelAvailabilityRS) o;
		}
		catch(ClassNotFoundException ex){
			ex.printStackTrace();
		}
		catch(IOException ex){
			ex.printStackTrace();
		}
		
		System.out.println("" + avrs1.getAvailableEstablishments().length + " hotels available online!");
		

		CavalHotelAvailabilityRS avrs2 = new HotelRatesTester().getAvailableHotels(avrq);

		System.out.println("***************************************");
		System.out.println("ONLINE --> CACHE");
		System.out.println(compare(avrs1, avrs2));
		System.out.println("***************************************");
		System.out.println("CACHE --> ONLINE");
		System.out.println(compare(avrs2, avrs1));
		System.out.println("***************************************");

	}

	/**
	 * compares both responses and prints out the result
	 * @param rs0 one response
	 * @param rs1 the other response
	 * @return the result of the comparison
	 */
	private static String compare(CavalHotelAvailabilityRS rs0, CavalHotelAvailabilityRS rs1) {
		StringWriter sw = new StringWriter();
		PrintWriter log = new PrintWriter(sw);
		int ok = 0;
		int ko = 0;
		for (AvailableEstablishment ae0 : rs0.getAvailableEstablishments()) 
			if ("".equals(idHotel) || ae0.getEstablishmentId().equals("ESACC" + idHotel) || ae0.getEstablishmentId().equals(idHotel))  //xxxxxxxxxx
			{
			boolean found = false;
			
			boolean ownProduct = false; 
			for (CombinationPrice cp0 : ae0.getPrices()) {
				if (!cp0.getRooms()[0].getRoomCode().startsWith("CAVAL")) ownProduct = true;
			}
			
			
			if (!ownProduct) {
				found = true;
			} else for (AvailableEstablishment ae1 : rs1.getAvailableEstablishments()) {
				if (ae0.getEstablishmentId().replace("ESACC", "").equals(ae1.getEstablishmentId().replace("ESACC", ""))) 
				{
					found = true;
					
					for (CombinationPrice cp0 : ae0.getPrices()) {
						boolean roomFound = false;
						
						if (!cp0.getRooms()[0].getRoomCode().startsWith("CAVAL")) {
							

							for (CombinationPrice cp1 : ae1.getPrices()) {
								if (cp0.getRooms()[0].getRoomCode().equals(cp1.getRooms()[0].getRoomCode())) {
									roomFound = true;
									for (BoardPrice bp0 : cp0.getBoardPrices()) {
										boolean boardFound = false;

										for (BoardPrice bp1 : cp1.getBoardPrices()) {
											if (bp0.getBoardCode().equals(bp1.getBoardCode())) {
												boardFound = true;
												if (Math.abs(bp0.getNetPrice().getValue() - bp1.getNetPrice().getValue()) > 1) {
													if (debug) log.println("hotel " + ae0.getEstablishmentId() + " - " + ae0.getEstablishmentName() + " - " + cp0.getRooms()[0].getRoomCode() + " - " + bp0.getBoardCode() + " not equal (" + bp0.getNetPrice().getValue() + " --> " + bp1.getNetPrice().getValue() + ")");
													ko++;
												} else ok++; 
												break;
											}
										}

										if (!boardFound) {
											if (debug) log.println("hotel " + ae0.getEstablishmentId() + " - " + ae0.getEstablishmentName() + " - " + cp0.getRooms()[0].getRoomCode() + " - " + bp0.getBoardCode() + " not found");
											ko++;
										}
									}								
									break;
								}
							}
						
							if (!roomFound) {
								if (debug) log.println("hotel " + ae0.getEstablishmentId() + " - " + ae0.getEstablishmentName() + " - " + cp0.getRooms()[0].getRoomCode() + " not found");
								for (BoardPrice bp0 : cp0.getBoardPrices()) ko++;
							}
						}
					}
					
					break;
				}
			}
			if (!found) {
				if (debug) log.println("hotel " + ae0.getEstablishmentId() + " - " + ae0.getEstablishmentName() + " not found");
				for (CombinationPrice cp0 : ae0.getPrices()) {
					for (BoardPrice bp0 : cp0.getBoardPrices()) {
						ko++;
					}
				}
			}
		}
		
		log.println(String.format("SUMMARY: %5.2f%% ok%n", new Double(100d * ok / (ok + ko))));
		
		return sw.toString();
	}

}
